package com.xjscrm.server.service.grouppulljob.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.uzai.trace.TraceGenerate;
import com.xjscrm.common.annotation.MerId;
import com.xjscrm.common.entity.GroupPullTask;
import com.xjscrm.common.utils.DateUtil;
import com.xjscrm.common.utils.Tools;
import com.xjscrm.server.biz.RatelimitService;
import com.xjscrm.server.dto.grouppulltask.GroupPullTaskQuery;
import com.xjscrm.server.mapper.GroupPullTaskMapper;
import com.xjscrm.server.service.grouppulljob.GroupPullJobService;
import com.xjscrm.server.service.grouppulljob.GroupPullTaskSyncService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 拉群任务异步实现类
 *
 * @author makejava
 * @since 2024-03-01 17:01:12
 */
@Slf4j
@Service
public class GroupPullTaskSyncServiceImpl implements GroupPullTaskSyncService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private GroupPullTaskMapper groupPullTaskMapper;
    @Autowired
    private RatelimitService ratelimitService;
    @Autowired
    private GroupPullJobService groupPullJobService;

    /**
     * 处理立即或者定时发送的拉群任务
     * @param merId
     * @return null
     * @author jitwxs
     * @date 2024/3/8 17:12
     */
    @Async("taskExecutorForXxJob")
    @TraceGenerate //注入消息id标签
    public void autoGroupPullTaskSyncByImmediately(@MerId Long merId){
        //限流key
        String taskLimitKet = "-autoGroupPullTaskSyncByImmediately-taskLimitKey-merId=" + merId;
        Object object = redisTemplate.opsForValue().get(taskLimitKet);
        if (object != null) {
            return;
        }
        //保存限流key
        redisTemplate.opsForValue().set(taskLimitKet, taskLimitKet, 100, TimeUnit.SECONDS);

        log.info("-----处理立即或者定时发送的拉群任务----merId=" + merId);

        try {
            //查询当前所有开启的自动发圈的配置方案
            int now = DateUtil.getTime();

            GroupPullTaskQuery groupPullTaskQuery = new GroupPullTaskQuery();
            groupPullTaskQuery.setMerId(merId);
            groupPullTaskQuery.setTypeList(Lists.newArrayList(0, 1)); //立即和定时任务
            groupPullTaskQuery.setSendTimeEnd(now+60);     //查询所有一分钟之内将要进行中的任务
            groupPullTaskQuery.setStatus(1); //进行中

            //查询所有的自动发圈配置记录
            Page<GroupPullTask> page = new Page<>();
            page.setCurrent(1);//只查第一页
            page.setSize(10); //每页查询10个
            page.addOrder(OrderItem.asc("id"));//默认id升序
            Long idStart = 0L;
            List<GroupPullTask> groupPullTaskList = groupPullTaskMapper.findByList(page, groupPullTaskQuery);
            while (groupPullTaskList != null && groupPullTaskList.size() > 0) {
                for (GroupPullTask groupPullTask : groupPullTaskList) {
                    if (groupPullTask.getId().longValue() >idStart.longValue()) {
                        idStart = groupPullTask.getId();
                    }

                    //限流判断
                    String rateLimitKey = "autoGroupPullTaskSyncByImmediately-taskId=" + groupPullTask.getId();
                    Object rateLimitKeyobject = redisTemplate.opsForValue().get(rateLimitKey);
                    if (rateLimitKeyobject == null) {
                        //保存限流key
                        redisTemplate.opsForValue().set(rateLimitKey, rateLimitKey, 300, TimeUnit.SECONDS);
                    } else {
                        continue;
                    }
                    try {

                        //处理拉群任务
                        groupPullTask.setHanderTime(groupPullTask.getSendTime());
                        groupPullJobService.addGroupPullJob(groupPullTask);

                        //处理完成，修改已完成
                        groupPullTask.setUpdateTime(DateUtil.getTime());
                        groupPullTask.setStatus(2); //已完成
                        groupPullTaskMapper.updateStatusById(groupPullTask);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }finally {
                        //保存成功之后，手动删除限流redisKey
                        redisTemplate.delete(rateLimitKey);
                    }
                }

                groupPullTaskQuery.setIdStart(idStart);
                groupPullTaskList = groupPullTaskMapper.findByList(page, groupPullTaskQuery);
            }
        } catch (Exception e) {
            log.info(e.getMessage(),e);
        } finally {
            //删除限流key
            redisTemplate.delete(taskLimitKet);
        }

    }

    /**
     * 处理循环的拉群任务
     * @param merId
     * @return null
     * @author jitwxs
     * @date 2024/3/8 17:12
     */
    @Async("taskExecutorForXxJob")
    @TraceGenerate //注入消息id标签
    public void autoGroupPullTaskSyncByCycle(@MerId Long merId){
        //限流key
        String taskLimitKet = "-autoGroupPullTaskSyncByCycle-taskLimitKey-merId=" + merId;
        Object object = redisTemplate.opsForValue().get(taskLimitKet);
        if (object != null) {
            return;
        }
        //保存限流key
        redisTemplate.opsForValue().set(taskLimitKet, taskLimitKet, 100, TimeUnit.SECONDS);

        log.info("-----处理循环的拉群任务----merId=" + merId);

        try {
            //查询当前所有开启的自动发圈的配置方案
            int now = DateUtil.getTime();

            GroupPullTaskQuery groupPullTaskQuery = new GroupPullTaskQuery();
            groupPullTaskQuery.setMerId(merId);
            groupPullTaskQuery.setTypeList(Lists.newArrayList(2, 3, 4)); //按时、按周、按日
            groupPullTaskQuery.setStatus(1); //进行中

            //查询所有的自动发圈配置记录
            Page<GroupPullTask> page = new Page<>();
            page.setCurrent(1);//只查第一页
            page.setSize(10); //每页查询10个
            page.addOrder(OrderItem.asc("id"));//默认id升序
            Long idStart = 0L;
            List<GroupPullTask> groupPullTaskList = groupPullTaskMapper.findByList(page, groupPullTaskQuery);
            while (groupPullTaskList != null && groupPullTaskList.size() > 0) {
                for (GroupPullTask groupPullTask : groupPullTaskList) {
                    if (groupPullTask.getId().longValue() >idStart.longValue()) {
                        idStart = groupPullTask.getId();
                    }

                    //限流判断
                    String rateLimitKey = "autoGroupPullTaskSyncByCycle-taskId=" + groupPullTask.getId();
                    Object rateLimitKeyobject = redisTemplate.opsForValue().get(rateLimitKey);
                    if (rateLimitKeyobject == null) {
                        //保存限流key
                        redisTemplate.opsForValue().set(rateLimitKey, rateLimitKey, 300, TimeUnit.SECONDS);
                    } else {
                        continue;
                    }

                    try {

                        //截止状态(0-不截止；1-截止)
                        Integer deadStatus = Tools.getInteger(groupPullTask.getDeadStatus());
                        if(deadStatus.intValue() == 1){ //如果是截止状态，则需要验证截止时间是否到期
                            //获取截止时间
                            Integer deadTime = Tools.getInteger(groupPullTask.getDeadTime());
                            //截止时间比当前时间小，则表示已经到期了，将此任务自动关闭
                            if(deadTime < now){
                                groupPullTask.setStatus(0); //已关闭
                                groupPullTask.setUpdateTime(now);
                                groupPullTask.setHanderTime(now);
                                groupPullTaskMapper.updateStatusById(groupPullTask);
                                continue;
                            }
                        }

                        //判断今天是否已经发送,根据发送时间来判断
                        if(groupPullTask.getSendTime() != null){ //已经处理过该任务，则需要判断当天是否已经处理过
                            Date sendTime_date = new Date(groupPullTask.getSendTime() * 1000L);
                            LocalDate localDate = sendTime_date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                            //发送时间和当前时间一样，表示当天已经处理过，不发送了
                            if(localDate.isEqual(LocalDate.now())){
                                continue;
                            }
                        }

                        boolean result = verifyTime(groupPullTask);
                        if(!result){
                            continue;
                        }

                        //处理拉群任务
                        //这次发送时间,当天日期+设置的发送时间
                        String sendTimeNewStr = DateUtil.today() + " " + groupPullTask.getTime() + ":00";
                        int sendTimeNew = (int) (DateUtil.parse(sendTimeNewStr, "yyyy-MM-dd HH:mm:ss").getTime() / 1000L);
                        groupPullTask.setHanderTime(sendTimeNew);
                        groupPullJobService.addGroupPullJob(groupPullTask);

                        //处理完成，修改已完成
                        groupPullTask.setUpdateTime(DateUtil.getTime());
                        groupPullTaskMapper.updateHanderTimeById(groupPullTask);
                    } catch (Exception e) {
                        log.info("自动拉群立即任务失败", e.getMessage(), e);
                    }finally {
                        //保存成功之后，手动删除限流redisKey
                        redisTemplate.delete(rateLimitKey);
                    }
                }

                groupPullTaskQuery.setIdStart(idStart);
                groupPullTaskList = groupPullTaskMapper.findByList(page, groupPullTaskQuery);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            //删除限流key
            redisTemplate.delete(taskLimitKet);
        }

    }

    /**
     * 验证循环任务是否已经轮到
     * @author jitwxs
     * @date 2024/4/2 9:36
     * @param groupPullTask 
     * @return boolean
     */
    public boolean verifyTime(GroupPullTask groupPullTask){

        if(groupPullTask == null ){
            return false;
        }

        //类型(0-立即发送；1-定时发送；2-每天发送；3-每周发送；4-每月发送)
        Integer type = Tools.getInteger(groupPullTask.getType());

        //只验证循环发送任务
        if(!Lists.newArrayList(2,3,4).contains(type)){
            return false;
        }

        if(type.intValue() == 3){ //每周发送
            List<Integer> weekList = JSONObject.parseArray(groupPullTask.getWeek(), Integer.class);
            if(weekList == null || weekList.size() == 0){
                return false;
            }
            //判断发送星期几
            LocalDate date = LocalDate.now();
            int dayOfWeek = date.getDayOfWeek().getValue();
            if(!weekList.contains(dayOfWeek)){
                return false;
            }
        }else if(type.intValue() == 4){
            List<Integer> dayList =  JSONObject.parseArray(groupPullTask.getDay(), Integer.class);
            if(dayList == null || dayList.size() == 0){
                return false;
            }
            LocalDate date = LocalDate.now();
            // 获取日
            int dayOfMonth = date.getDayOfMonth();
            if(!dayList.contains(dayOfMonth)){
                return false;
            }
        }

        //发送时间（HH:mm）
        String time = groupPullTask.getTime();
        if (StringUtils.isBlank(time)) {
            time = "00:00";
        }

        //允许发送区间开始时间=提前30分钟
        LocalTime limitTimeStartLocal = LocalTime.parse(time).minusMinutes(30);
        //允许发送区间结束时间=延后1分钟
        LocalTime limitTimeEndLocal = LocalTime.parse(time).plusMinutes(1);

        //判断当前时间是否在自动任务开启时间区间内
        boolean withinTimeInterval = Tools.isWithinTimeInterval(LocalDateTime.now(), limitTimeStartLocal, limitTimeEndLocal);
        //不在区间内，则跳过
        if (!withinTimeInterval) {
            return false;
        }

        return false;
    }
    
}
